package com.customization.qs.download.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.customization.qs.download.service.SpecialWorkflowBatchDownloadService;
import com.customization.qs.download.util.DownLoadUtils;
import com.engine.core.impl.Service;
import org.apache.commons.lang.StringUtils;
import weaver.conn.RecordSet;
import weaver.general.GCONST;
import weaver.integration.logging.Logger;
import weaver.integration.logging.LoggerFactory;
import weaver.system.SystemComInfo;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import de.schlichtherle.util.zip.ZipEntry;
import de.schlichtherle.util.zip.ZipOutputStream;

public class SpecialWorkflowBatchDownloadServiceImpl extends Service implements SpecialWorkflowBatchDownloadService {

    private static Logger log = LoggerFactory.getLogger(SpecialWorkflowBatchDownloadServiceImpl.class);

    @Override
    public JSONObject batchDownloadFile(String workflowId, String requestId, String nodeId, HttpServletRequest request, HttpServletResponse response) throws Exception {

        // workflow_nodeform 当前节点字段是否可见 isview  0：否 1：是
        // workflow_billfield 数据库表字段名称 fieldname
        //                    单据字段页面类型 fieldhtmltype 3：浏览按钮 6：上传附件
        //                    单据字段详细类型 type  9：文档 37：多文档
        //                    主表字段还是从表字段 viewtype  0：主表 1：从表
        //                    明细表 detailtable  　
        RecordSet rs = new RecordSet();
        String sql = "select wr.requestname,wfb.tablename,wbf.detailtable,wbf.fieldname,wbf.viewtype,wbf.fieldhtmltype " +
                "from workflow_requestbase wr " +
                "join workflow_flownode wfn on wr.workflowid = wfn.workflowid " +
                "join workflow_nodebase wnb on wfn.nodeid = wnb.id " +
                "join workflow_nodeform wnf on wfn.nodeid = wnf.nodeid " +
                "join workflow_billfield wbf on wnf.fieldid = wbf.id " +
                "join workflow_bill wfb on wfb.id = wbf.billid " +
                "where wnf.isview = 1 and wr.workflowid = ?  and wr.requestid = ? and  wfn.nodeid = ? and ((wbf.type = 37 or wbf.type = 9) or wbf.fieldhtmltype = 6) ";
        rs.executeQuery(sql, workflowId, requestId, nodeId);

        List<JSONObject> mainFjList = new ArrayList<>();
        List<JSONObject> mainWdList = new ArrayList<>();
        List<JSONObject> subFjList = new ArrayList<>();
        List<JSONObject> subWdList = new ArrayList<>();

        String mainTableName = "";
        String zipName = "";
        while (rs.next()) {
            String tableName = rs.getString("tablename");
            if (!StringUtils.isNotBlank(mainTableName)) {
                mainTableName = tableName;
            }

            String requestName = rs.getString("requestname");
            if (!StringUtils.isNotBlank(zipName)) {
                requestName = requestName.trim().replaceAll("[/\\\\!@#$&*()=:/;?+'\\\"]", "_");
                zipName = requestName;
            }

            // 主表字段还是从表字段 viewtype  0：主表 1：从表
            String viewType = rs.getString("viewtype");
            // 单据字段页面类型 fieldhtmltype 3：浏览按钮 6：上传附件
            String fieldHtmlType = rs.getString("fieldhtmltype");

            String detailTable = rs.getString("detailtable");
            String fieldName = rs.getString("fieldname").trim();

            String sqlQuery = "";
            JSONObject json = new JSONObject();
            if ("3".equals(fieldHtmlType)) {
                // 文档
                if ("0".equals(viewType)) {
                    // 主表
                    if (StringUtils.isNotBlank(tableName) && StringUtils.isNotBlank(fieldName)) {
                        sqlQuery = "select " + fieldName + " from " + tableName + " where requestId=? ";
                        json.put(fieldName, sqlQuery);
                        mainWdList.add(json);
                    }
                } else {
                    // 子表
                    if (StringUtils.isNotBlank(detailTable) && StringUtils.isNotBlank(fieldName)) {
                        sqlQuery = "select " + fieldName + " from " + detailTable + " where mainid=? ";
                        ;
                        json.put(fieldName, sqlQuery);
                        subWdList.add(json);
                    }
                }
            }
            if ("6".equals(fieldHtmlType)) {
                // 附件上传
                if ("0".equals(viewType)) {
                    // 主表
                    if (StringUtils.isNotBlank(tableName) && StringUtils.isNotBlank(fieldName)) {
                        sqlQuery = "select " + fieldName + " from " + tableName + " where requestId=? ";
                        json.put(fieldName, sqlQuery);
                        mainFjList.add(json);
                    }
                } else {
                    if (StringUtils.isNotBlank(detailTable) && StringUtils.isNotBlank(fieldName)) {
                        sqlQuery = "select " + fieldName + " from " + detailTable + " where mainid=? ";
                        ;
                        json.put(fieldName, sqlQuery);
                        subFjList.add(json);
                    }
                }
            }
        }
        log.info("mainFjList:" + mainFjList);
        log.info("subFjList:" + subFjList);
        log.info("mainWdList:" + mainWdList);
        log.info("subWdList:" + subWdList);
        // 查询主表id
        sql = "select id from " + mainTableName + " where requestId=? ";
        log.info("查询主表id-sql:" + sql);
        rs.executeQuery(sql, requestId);

        if (rs.next()) {
            String mainId = rs.getString("id");
            log.info("mainId:" + mainId);
            if (StringUtils.isNotBlank(mainId)) {
                List<String> fjIds = new ArrayList<>();
                List<String> wdIds = new ArrayList<>();

                // 主附件查询
                for (JSONObject json : mainFjList) {
                    for (Object key : json.keySet()) {
                        String keyStr = String.valueOf(key);
                        sql = json.getString(keyStr);
                        rs.executeQuery(sql, requestId);
                        if (rs.next()) {
                            String fjId = rs.getString(keyStr);
                            if (StringUtils.isNotBlank(fjId)) {
                                if (!fjIds.contains(fjId)) {
                                    fjIds.add(fjId);
                                }
                            }
                        }
                    }
                }

                // 主文档查询
                for (JSONObject json : mainWdList) {
                    for (Object key : json.keySet()) {
                        String keyStr = String.valueOf(key);
                        sql = json.getString(keyStr);
                        rs.executeQuery(sql, requestId);
                        if (rs.next()) {
                            String wdId = rs.getString(keyStr);
                            if (StringUtils.isNotBlank(wdId)) {
                                if (!wdIds.contains(wdId)) {
                                    wdIds.add(wdId);
                                }
                            }
                        }
                    }
                }

                // 子附件查询
                for (JSONObject json : subFjList) {
                    for (Object key : json.keySet()) {
                        String keyStr = String.valueOf(key);
                        sql = json.getString(keyStr);
                        rs.executeQuery(sql, mainId);
                        // 多条
                        while (rs.next()) {
                            String fjId = rs.getString(keyStr);
                            if (StringUtils.isNotBlank(fjId)) {
                                if (!fjIds.contains(fjId)) {
                                    fjIds.add(fjId);
                                }
                            }
                        }
                    }
                }

                // 子文档查询
                for (JSONObject json : subWdList) {
                    for (Object key : json.keySet()) {
                        String keyStr = String.valueOf(key);
                        sql = json.getString(keyStr);
                        rs.executeQuery(sql, mainId);
                        // 多条
                        while (rs.next()) {
                            String wdId = rs.getString(keyStr);
                            if (StringUtils.isNotBlank(wdId)) {
                                if (!wdIds.contains(wdId)) {
                                    wdIds.add(wdId);
                                }
                            }
                        }
                    }
                }
                log.info("fjIds:" + fjIds);

                try {
                    SystemComInfo comInfo = new SystemComInfo();
                    String fileFolder = comInfo.getFilesystem();

                    if (!StringUtils.isNotBlank(fileFolder)) {
                        fileFolder = GCONST.getRootPath();
                        fileFolder = fileFolder + "filesystem" + File.separatorChar;
                    } else {
                        if (!fileFolder.endsWith(File.separator)) {
                            fileFolder += File.separator;
                        }
                    }
                    log.info("fileFolder:" + fileFolder);
                    String dateFormat = new SimpleDateFormat("yyyy-MM-dd").format(new Date());

                    String fileTempFolder = fileFolder + "downloadBatchTemp" + File.separatorChar + "thirdBatchTemp" + File.separatorChar + dateFormat + File.separatorChar;
                    String fileRealFolder = fileFolder + "downloadBatch" + File.separatorChar + "thirdBatch" + File.separatorChar + dateFormat + File.separatorChar;

                    List<String> fileRealPathList = new ArrayList<>();
                    List<String> fileRealPathTempList = new ArrayList<>();

                    // 附件id集合
                    if (fjIds.size() > 0) {
                        String fjIdsStr = String.join(",", fjIds);
                        log.info("fjIdsStr:" + fjIdsStr);
                        DownLoadUtils.getAttachmentInfo(fjIdsStr, fileTempFolder, fileRealPathList, fileRealPathTempList);
                    }
                    log.info("wdIds:" + wdIds);
                    // 文档id集合
                    if (wdIds.size() > 0) {
                        String wdIdsStr = String.join(",", wdIds);
                        log.info("wdIdsStr:" + wdIdsStr);
                        DownLoadUtils.getDocInfo(wdIdsStr, fileTempFolder, fileRealPathList, fileRealPathTempList);
                    }

                    if (fjIds.size() > 0 || wdIds.size() > 0) {
                        log.info("fileRealPathList:" + fileRealPathList);
                        log.info("fileRealPathTempList:" + fileRealPathTempList);

                        // 整合文件，判断是否需要打成压缩包
                        int size = fileRealPathTempList.size();
                        File[] files = new File[size];
                        for (int i = 0; i < size; i++) {
                            String fileRealPath = fileRealPathTempList.get(i);
                            files[i] = new File(fileRealPath);
                        }

                        // 压缩包命名
                        String tmpfileName = zipName + "_" + dateFormat + "_批量下载文件.zip";

                        String zipPath = fileRealFolder + tmpfileName;
                        log.info("zipPath:" + zipPath);
                        File file = DownLoadUtils.fileCreate(fileRealFolder, tmpfileName);

                        String strzipName = file.getPath();
                        ZipOutputStream zout = null;
                        if (file.exists()) {
                            try {
                                log.info("开始打压缩包！");
                                zout = new ZipOutputStream(new FileOutputStream(strzipName), "UTF-8");
                                byte[] bt = new byte[8192];
                                for (File filez : files) {
                                    try {
                                        FileInputStream is = new FileInputStream(filez);
                                        ZipEntry ze = new ZipEntry(filez.getName());
                                        zout.putNextEntry(ze);
                                        int len;
                                        // 读取下载文件内容
                                        while ((len = is.read(bt)) > 0) {
                                            zout.write(bt, 0, len);
                                        }
                                        zout.closeEntry();
                                        is.close();

                                    } catch (Exception e) {
                                        log.error("读取下文件流异常：" + e.getMessage());
                                    }
                                }
                                zout.flush();
                            } catch(Exception e){
                                log.error("输出文件流异常：" + e.getMessage());
                                throw new Exception("压缩包输出文件流异常：" + e.getMessage());
                            } finally{
                                if (zout != null) {
                                    try {
                                        zout.flush();
                                        zout.close();
                                    } catch (Exception ex) {
                                        log.error("关闭zout文件流异常：" + ex.getMessage());
                                    }
                                }
                            }

                            // DownLoadUtils.downloadFile(request, response, tmpfileName, zipPath);

                            if (StringUtils.isNotBlank(zipPath)) {
                                File zipFile = new File(zipPath);
                                if (zipFile.exists()) {
                                    String fileOfBase64 = DownLoadUtils.convertFileToBase64(file);

                                    if(StringUtils.isNotBlank(fileOfBase64)){
                                        JSONObject jsonObject = new JSONObject();
                                        jsonObject.put("file",fileOfBase64);
                                        jsonObject.put("size",zipFile.length());
                                        jsonObject.put("fileName",tmpfileName);
                                        deleteFiles(strzipName,fileTempFolder,fileRealFolder);

                                        return jsonObject;
                                    }else {
                                        log.error("文件转base64为空！");
                                        deleteFiles(strzipName,fileTempFolder,fileRealFolder);
                                    }
                                } else {
                                    deleteFiles(strzipName,fileTempFolder,fileRealFolder);
                                    log.error("压缩文件不存在！");
                                }
                            }else {
                                log.error("压缩包地址为空！");
                                deleteFiles(strzipName,fileTempFolder,fileRealFolder);
                            }
                            return null;
                        }else{
                            log.error("压缩包创建失败！");
                            throw new Exception("压缩包创建失败！");
                        }
                    } else {
                        log.error("没有可以下载的文件！");
                        throw new Exception("没有可以下载的文件！");
                    }
                } catch (Exception ex) {
                    log.error(ex.getMessage());
                    throw new Exception(ex.getMessage());
                }
            } else {
                log.error("查询流程数据异常！");
                throw new Exception("查询流程数据异常！");
            }
        } else {
            log.error("查询流程数据异常！");
            throw new Exception("查询流程数据异常！");
        }
    }


    private void deleteFiles(String strzipName,String fileTempFolder,String fileRealFolder){
        try {

            DownLoadUtils.deleteFile(strzipName);

            DownLoadUtils.deleteFile(fileTempFolder);

            DownLoadUtils.deleteFile(fileRealFolder);

        }catch (Exception e){
            log.error("清理文件异常！"+e.getMessage());
        }
    }
}
